﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using ScrumFactory.Composition.ViewModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using ScrumFactory.Composition;
using ScrumFactory.Services;
using System.Collections.ObjectModel;

namespace ScrumFactory.ProjectTeam.ViewModel {

    /// <summary>
    /// Roles List View Model.
    /// </summary>
    [Export(typeof(IRolesListViewModel))]
    public class RolesListViewModel : BasePanelViewModel, IRolesListViewModel, IPanelViewModel, INotifyPropertyChanged {

        private IEventAggregator aggregator;
        private IProjectsService projectsServices;
        private IBackgroundExecutor executor;

        private IRoleViewModel selectedRole;
        private Role oldSelectedRole;
        
        [ImportingConstructor]
        public RolesListViewModel(
            [Import]IEventAggregator eventAggregator,
            [Import]IProjectsService projectsServices,
            [Import]IBackgroundExecutor backgroundExecutor
            ) {

            this.aggregator = eventAggregator;
            this.projectsServices = projectsServices;
            this.executor = backgroundExecutor;

            aggregator.Subscribe<Project>(ScrumFactoryEvent.ViewProjectDetails, OnViewProjectDetails);
         

            CloseWindowCommand = new DelegateCommand(CloseWindow);
            AddNewRoleCommand = new DelegateCommand(AddNewRole);
            DeleteRoleCommand = new DelegateCommand<IRoleViewModel>(DeleteRole);
        }

        private void OnViewProjectDetails(Project project) {
            Project = project;            
            CreateRoleViewModels();
        }
      
        private void CreateRoleViewModels() {
            if (Project.Roles == null)
                Project.Roles = new List<Role>();
            
            Roles = new ObservableCollection<IRoleViewModel>();
            if (Project.Roles != null) {
                foreach (Role r in Project.Roles) {
                    Roles.Add(new RoleViewModel(r));
                }
            }
            OnPropertyChanged("Roles");
            aggregator.Publish<ICollection<Role>>(ScrumFactoryEvent.ProjectRolesLoaded, Project.Roles);
        }

        private IRoleViewModel roleToBeDeleted = null;
        private void DeleteRole(IRoleViewModel roleVM) {
            roleToBeDeleted = roleVM;
            
            executor.StartBackgroundTask(
                () => {                    
                    projectsServices.DeleteProjectRole(roleVM.Role.ProjectUId, roleVM.Role.RoleUId);
                    roleToBeDeleted.JustHasBeenRemoved = true;
                    System.Threading.Thread.Sleep(500); // ugly no? this is just to give time for the remove animation take do its job
                },
                OnProjectRoleDeleted);
        }

        private void OnProjectRoleDeleted() {            
            Project.Roles.Remove(roleToBeDeleted.Role);
            Roles.Remove(roleToBeDeleted);
            aggregator.Publish<ICollection<Role>>(ScrumFactoryEvent.ProjectRolesLoaded, Project.Roles);
            roleToBeDeleted = null;
        }
      

        private void AddNewRole() {
            Role newRole = new Role() { ProjectUId = Project.ProjectUId, RoleUId = Guid.NewGuid().ToString(), RoleName = Properties.Resources.New_role_name, PermissionSet = 0, IsPlanned = true };
            Project.Roles.Add(newRole);

            IRoleViewModel roleVm = new RoleViewModel(newRole);
            roleVm.JustHasBeenInserted = true;
            Roles.Add(roleVm);
            

            SelectedRole = roleVm;

            executor.StartBackgroundTask(() => {                
                projectsServices.UpdateProjectRole(SelectedRole.Role.ProjectUId, newRole);
            }, () => { });

            aggregator.Publish<ICollection<Role>>(ScrumFactoryEvent.ProjectRolesLoaded, Project.Roles);
        }
 
        /// <summary>
        /// Closes the window, invoke the OnCloseAction and publishes the CloseWindow event.
        /// </summary>
        private void CloseWindow() { 
            if(HasRoleChanged)           
                SaveOldRole();
            aggregator.Publish<IPanelViewModel>(ScrumFactoryEvent.CloseWindow, (IPanelViewModel)this);            
        }


        private bool HasRoleChanged {
            get {
                if (oldSelectedRole == null)
                    return false;
                Role actualRole = Project.Roles.SingleOrDefault(r => r.RoleUId == oldSelectedRole.RoleUId);
                if (actualRole == null)
                    return false;
                return !actualRole.IsTheSame(oldSelectedRole);
            }
        }

        private void SaveOldRole() {
            if (oldSelectedRole == null)
                return;
            Role actualRole = Project.Roles.SingleOrDefault(r => r.RoleUId == oldSelectedRole.RoleUId);
            if (actualRole==null)
                return;

            aggregator.Publish<Role>(ScrumFactoryEvent.ProjectRoleChanged, actualRole);

            executor.StartBackgroundTask(() => {
                projectsServices.UpdateProjectRole(SelectedRole.Role.ProjectUId, actualRole);
            }, () => { });              
        }


        [Import]
        public IRolesListView View { get; set; }

        
        #region IRolesListViewModel Members

        /// <summary>
        /// Gets the project.
        /// </summary>
        /// <value>The project.</value>
        public Project Project { get; private set; }

        /// <summary>
        /// Gets the roles.
        /// </summary>
        /// <value>The roles.</value>
        public ICollection<IRoleViewModel> Roles { get; private set; }

        /// <summary>
        /// Gets or sets the selected role.
        /// </summary>
        /// <value>The selected role.</value>
        public IRoleViewModel SelectedRole {
            get {
                return selectedRole;
            }
            set {
                if (HasRoleChanged) 
                    SaveOldRole();
                                    
                if (value != null && value.Role != null)
                    oldSelectedRole = value.Role.Clone();
                else
                    oldSelectedRole = null;
                
                selectedRole = value;
                OnPropertyChanged("SelectedRole");
            }
        }
        
        /// <summary>
        /// Gets the add new role command.
        /// </summary>
        /// <value>The add new role command.</value>
        public ICommand AddNewRoleCommand { get; private set; }

        /// <summary>
        /// Gets the remove role command.
        /// </summary>
        /// <value>The remove role command.</value>
        public ICommand DeleteRoleCommand { get; private set; }

        /// <summary>
        /// Gets the close window command.
        /// </summary>
        /// <value>The close window command.</value>
        public ICommand CloseWindowCommand { get; private set; }

        #endregion

        #region IPanelViewModel Members

        /// <summary>
        /// Gets the name of the panel.
        /// </summary>
        /// <value>The name of the panel.</value>
        public string PanelName {
            get {
                return Properties.Resources.Roles;
            }
        }

        /// <summary>
        /// Gets the view.
        /// </summary>
        /// <value>The view.</value>
        object IPanelViewModel.View {
            get {
                return this.View;
            }
        }

        /// <summary>
        /// Gets the panel display order when it is displayed at the view.
        /// </summary>
        /// <value>The panel display order.</value>
        public int PanelDisplayOrder {
            get { return 0; }
        }

        /// <summary>
        /// Gets the panel Unique id.
        /// </summary>
        /// <value>The panel Unique id.</value>
        public string PanelUId {
            get { return "PROJECT_ROLES"; }
        }

        /// <summary>
        /// Gets the panel placement.
        /// </summary>
        /// <value>The panel placement.</value>
        public PanelPlacements PanelPlacement {
            get {
                return PanelPlacements.MainPanel;
            }
        }

        #endregion

 
    }
}
